package pl.edu.pb.wi.pwnography.controller;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import pl.edu.pb.wi.pwnography.model.form.MasterForm;
import pl.edu.pb.wi.pwnography.model.form.OutlierDetectionForm;
import pl.edu.pb.wi.pwnography.modules.OutlierDetection;
import pl.edu.pb.wi.pwnography.session.FileList;

@Controller
@RequestMapping("/module/outlierdetection")
public class OutlierDetectionModule {
    private static final String OUTLIERDETECTION_ERROR = "W trakcie wykrywania wartości odstających wystąpił błąd.";
    private static final String OUTLIERDETECTION_SUCCESS = "Wartości odstające zostały poprawnie wykryte dla kolumny %s.";
    private static final String PERCENTAGE_DESCRIPTION = "Wykrywanie wartości odstających metodą określonego procentu %f%% dla kolumny %s.";
    private static final String STANDARDDEVIATION_DESCRIPTION = "Wykrywanie wartości odstających metodą potrójnego odchylenia standardowego dla kolumny %s.";

    private static final Logger log = Logger
	    .getLogger(OutlierDetectionModule.class.getName());

    @Autowired
    private FileList fileList;

    public void setFileList(FileList fileList) {
	this.fileList = fileList;
    }

    @ModelAttribute("floatColumnList")
    public List<String> getFloatColumnNames() {
	return fileList.getActiveFile().getFloatTypeColumnNames();
    }

    @RequestMapping(value = "standarddeviation", method = RequestMethod.GET)
    public String standardDeviation(Model model) {
	log.info("Outlier detection standard deviation GET.");

	model.addAttribute("form", new MasterForm());

	return "module/outlierdetection/standarddeviation";
    }

    @RequestMapping(value = "standarddeviation", method = RequestMethod.POST)
    public String standardDeviation(
	    @ModelAttribute("form") @Valid MasterForm form,
	    BindingResult results, Model model) {
	log.info("Outlier detection standard deviation POST.");

	if (results.hasErrors()) {
	    return "module/outlierdetection/standarddeviation";
	}

	try {
	    Map<String, List<Object>> data = OutlierDetection
		    .standardDeviation(
			    form.getColumnName(),
			    fileList.getActiveFile().getColumnValues(
				    form.getColumnName()),
			    form.getResultColumnName());

	    String description = String.format(STANDARDDEVIATION_DESCRIPTION,
		    form.getColumnName());

	    fileList.getActiveFile().addNewRevision(data, description);

	    log.info(fileList.getActiveFile().getCurrentRevisionData()
		    .toString());

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(
			    OUTLIERDETECTION_SUCCESS, form.getColumnName()) }));
	} catch (Exception e) {
	    log.info(String
		    .format("Problem with outlier detection standard deviation . Exception: %s",
			    e.getMessage()));

	    model.addAttribute("errorMsgs",
		    Arrays.asList(new String[] { OUTLIERDETECTION_ERROR }));
	}

	return "module/outlierdetection/standarddeviation";
    }

    @RequestMapping(value = "percentage", method = RequestMethod.GET)
    public String percentage(Model model) {
	log.info("Outlier detection percentage GET.");

	model.addAttribute("form", new OutlierDetectionForm());

	return "module/outlierdetection/percentage";
    }

    @RequestMapping(value = "percentage", method = RequestMethod.POST)
    public String percentage(
	    @ModelAttribute("form") @Valid OutlierDetectionForm form,
	    BindingResult results, Model model) {
	log.info("Outlier detection percentage POST.");

	if (form.getPercentage() != null && form.getPercentage() < 1) {
	    results.addError(new FieldError("form", "percentage",
		    "Wartość musi być większa lub równa 1."));
	}

	if (form.getPercentage() != null && form.getPercentage() > 100) {
	    results.addError(new FieldError("form", "percentage",
		    "Wartość musi być mniejsza lub równa 100."));
	}

	if (results.hasErrors()) {
	    return "module/outlierdetection/percentage";
	}

	try {
	    Map<String, List<Object>> data = OutlierDetection.percentage(
		    form.getColumnName(),
		    fileList.getActiveFile().getColumnValues(
			    form.getColumnName()), form.getPercentage(), form
			    .getResultColumnName());

	    String description = String.format(PERCENTAGE_DESCRIPTION,
		    form.getPercentage(), form.getColumnName());

	    fileList.getActiveFile().addNewRevision(data, description);

	    log.info(fileList.getActiveFile().getCurrentRevisionData()
		    .toString());

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(
			    OUTLIERDETECTION_SUCCESS, form.getColumnName()) }));
	} catch (Exception e) {
	    log.info(String
		    .format("Problem with outlier detection percentage . Exception: %s",
			    e.getMessage()));

	    model.addAttribute("errorMsgs",
		    Arrays.asList(new String[] { OUTLIERDETECTION_ERROR }));
	}

	return "module/outlierdetection/percentage";
    }

}
